package com.app.service.impl.article;

import com.app.domain.bo.article.ArticleBo;
import com.app.domain.page.Page;
import com.app.domain.po.MenuPo;
import com.app.domain.po.article.ArticlePo;
import com.app.domain.po.user.UserPo;
import com.app.domain.vo.MenuVo;
import com.app.domain.vo.article.ArticleContentVo;
import com.app.domain.vo.article.ArticleCountVo;
import com.app.domain.vo.article.ArticleTagVo;
import com.app.domain.vo.article.ArticleVo;
import com.app.domain.vo.user.UserVo;
import com.app.framework.utils.*;
import com.app.mapper.article.ArticleMapper;
import com.app.service.MenuService;
import com.app.service.article.*;
import com.app.service.user.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import jakarta.annotation.Resource;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.*;

/**
 * 文章方法实现
 */
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, ArticlePo> implements ArticleService {

    @Resource
    private UserService userService;

    @Resource
    private MenuService menuService;

    @Resource
    private ArticleTagService articleTagService;

    @Resource
    private ArticleCountService articleCountService;

    @Resource
    private ArticleCommonService articleCommonService;

    @Resource
    private ArticleContentService articleContentService;

    /**
     * 文章列表
     *
     * @param bo 入参
     */
    @Override
    public Page<ArticleVo> lists(ArticleBo bo) {
        PageHelper.startPage(bo.getPageNum(), bo.getPageSize());
        List<ArticleVo> articleVos = baseMapper.lists(bo);
        if (CollectionUtils.isEmpty(articleVos)) {
            return Page.restPage(new ArrayList<>());
        }
        articleCountService.batchSetArticleCounts(articleVos);
        articleCommonService.batchSetMenuAndUser(articleVos);
        return Page.restPage(articleVos);
    }

    /**
     * 标签筛选文章
     *
     * @param bo 入参
     */
    @Override
    public Page<ArticleVo> articleTags(ArticleBo bo) {
        List<Long> articleIds = articleTagService.selectArticleIdsByTagIds(bo.getTagIds());
        List<ArticleVo> articleVos;
        if (CollectionUtils.isNoNull(articleIds)) {
            PageHelper.startPage(bo.getPageNum(), bo.getPageSize());
            List<ArticlePo> articlePos = baseMapper.selectBatchIds(articleIds);
            articleVos = CoBeanUtils.copyList(articlePos, ArticleVo.class);
        } else {
            return Page.restPage(new ArrayList<>());
        }
        articleCountService.batchSetArticleCounts(articleVos);
        articleCommonService.batchSetMenuAndUser(articleVos);
        return Page.restPage(articleVos);
    }

    /**
     * 热门文章
     */
    @Override
    @Cacheable(cacheNames = "article_hots", cacheManager = "cache1Day")
    public Page<ArticleVo> articleHots(ArticleBo bo) {
        PageHelper.startPage(bo.getPageNum(), bo.getPageSize());
        List<ArticleVo> articleVos = baseMapper.articleHots();
        articleCountService.batchSetArticleCounts(articleVos);
        articleCommonService.batchSetMenuAndUser(articleVos);
        return Page.restPage(articleVos);
    }

    /**
     * 文章详情
     *
     * @param articleId 文章ID
     */
    @Override
    public ArticleVo details(Long articleId) {
        String redisKey = "article_details";
        ArticleVo articleVo;
        if (RedisUtils.existsHashField(redisKey, articleId)) {
            articleVo = RedisUtils.getJsonHash(redisKey, articleId, ArticleVo.class);
        } else {
            ArticlePo articlePo = baseMapper.selectById(articleId);
            Assert.notNull(articlePo, "文章不存在");
            articleVo = CoBeanUtils.copy(articlePo, ArticleVo.class);
            //文章标签
            List<ArticleTagVo> articleTagVos = articleTagService.selectArticleTags(articleId);
            articleVo.setArticleTags(articleTagVos);
            //作者信息
            UserPo userPo = userService.getById(articleVo.getUserId());
            articleVo.setUser(CoBeanUtils.copy(userPo, UserVo.class));
            //所属菜单
            MenuPo menuPo = menuService.getById(articleVo.getMenuId());
            articleVo.setMenu(CoBeanUtils.copy(menuPo, MenuVo.class));
            //文章内容
            ArticleContentVo articleContentVo = articleContentService.selectArticleContent(articleId);
            articleVo.setContent(articleContentVo.getContent());
            articleVo.setContentMd(articleContentVo.getContentMd());
            //返回img数组(从content中正则)
            articleVo.setArticleImages(ImgUtils.getImgSrcList(articleContentVo.getContent()));
            //写入缓存
            RedisUtils.setJsonHash(redisKey, articleId, articleVo);
        }
        //更新文章访问数量
        articleCountService.updateArticleLooks(articleId);
        //文章计数器
        articleVo.setArticleCount(articleCountService.selectArticleCounts(articleId));
        return articleVo;
    }

    /**
     * 添加文章
     *
     * @param bo 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOne(ArticleBo bo) {
        Long loginUserId = TokenUtils.getLoginUserId();
        ArticlePo articlePo = CoBeanUtils.copy(bo, ArticlePo.class);
        articlePo.setUserId(loginUserId);
        articlePo.setCreateTime(new Date());
        baseMapper.insert(articlePo);
        Long articleId = articlePo.getId();
        String articleContent = bo.getContent();
        String articleContentMd = bo.getContentMd();
        articleTagService.updateTags(bo.getTagIds(), articleId);
        articleContentService.saveOne(articleId, articleContent, articleContentMd);
    }

    /**
     * 修改文章
     *
     * @param bo 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOne(ArticleBo bo) {
        Long loginUserId = TokenUtils.getLoginUserId();
        Long articleId = bo.getId();
        ArticlePo articlePo = baseMapper.selectById(articleId);
        Assert.notNull(articlePo, "文章不存在");
        String articleContent = bo.getContent();
        String articleContentMd = bo.getContentMd();
        Assert.state(articlePo.getUserId().equals(loginUserId), "不可以修改非自己的文章");
        CoBeanUtils.copyProperties(bo, articlePo);
        articlePo.setUpdateTime(new Date());
        baseMapper.updateById(articlePo);
        if (CollectionUtils.isNoNull(bo.getTagIds())) {
            articleTagService.updateTags(bo.getTagIds(), articleId);
        }
        if (CollectionUtils.isNoNull(articleContent)) {
            articleContentService.updateOne(articleId, articleContent, articleContentMd);
        }
        RedisUtils.deleteJsonHash("article_details", articleId);
    }

    /**
     * 删除文章
     *
     * @param articleId 文章ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteOne(Long articleId) {
        Long loginUserId = TokenUtils.getLoginUserId();
        ArticlePo articlePo = baseMapper.selectById(articleId);
        Assert.notNull(articlePo, "文章不存在");
        Long articleUserId = articlePo.getUserId();
        Assert.state(articleUserId.equals(loginUserId), "不能删除Ta人文章");
        baseMapper.deleteById(articleId);
        //删除文章内容
        baseMapper.deleteArticleContent(articleId);
        //删除所有评论
        baseMapper.deleteArticleComments(articleId);
        //删除文章的标签记录
        baseMapper.deleteArticleTags(articleId);
        //删除文章弹幕
        baseMapper.deleteArticleDanmus(articleId);
        //模糊匹配删除缓存
        RedisUtils.deleteKeysContaining("article");
    }

}